package Negocio;

import Negocio.Cola.Contenedor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JOptionPane;

/**
 *
 * @author
 */
public class Escalada2 extends MetodoBusqueda {

    private Contenedor<Hoja> abierto;
    private Hoja m;

    public Escalada2() {
        abierto = new Contenedor<Hoja>();
        m = null;
    }

    @Override
    public List<Estado> obtenerOptimo() {
        List<Estado> optimo = new ArrayList<Estado>();
        List<Hoja> camino = arbol.getCaminoOptimo();

        for (int i = 0; i < camino.size(); i++) {
            optimo.add(camino.get(i).getEstado());
        }
        return optimo;
    }

    public void procesar(){
//      1. Denominar m al estado inicial y evaluarlo. Si es estado objetivo,
//      entonces devolverlo y terminar, si no, convertirlo en estado actual.
//      Asignar m a una varibla llamada elegido.

//      2. Repetir hasta que se encuentre solución o hasta que una
//      iteración completa no produzca un cambio en el estado actual:

//          2.1 Expandir m creando el conjunto de todos sus sucesores.

//              2.1.A. Aplicar cada operador aplicable al estado actual m y conseguir
//                 nuevos estados E1, ... En.

//              2.1.B. Evaluar E1 .... En. Si alguno es objetivo, devolverlo y terminar Si
//              no es así, seleccionar el mejor H(Em)

//              2.1.C. Si el mejor estado Em es mejor que el estado actual, hacer que
//              Em sea el estado actual. Volver al paso 2.
//**            Si no es así, buscar el padre del estado actual, calcular sus sucesores
//**            y eliminar de ellos a estado actual. Volver a a 2.1.B.



        boolean tieneHijosMejores = true;
        boolean raizSinHijosMejores = false;
        iniciarArbol();

        List<Hoja> optimo = new ArrayList<Hoja>();
        Hoja raiz = arbol.getRaiz();
        Hoja hojaActual = raiz;
        Hoja mejorTemp = null;

        List<Hoja> hojasAEvitar = new ArrayList<Hoja>();
        boolean fin = false;
        //1.
        optimo.add(hojaActual);
        if (raiz.esEstadoFinal()) {
            hojaActual.setEsCamino(true);

            arbol.setCaminoOptimo(optimo);
            return;
        } else {
            while(true){
                List<Hoja> hijos = null;
                if(!tieneHijosMejores){
                    if(hojaActual.getPadre() != null){
                        //2.1.C.
                        Hoja padre = hojaActual.getPadre();
                        arbol.cargarHijosDinamico(padre);
                        hijos = padre.getHijos();
//                        hijos.remove(hojaActual);
                        if(!hojasAEvitar.contains(hojaActual)){
                            hojasAEvitar.add(hojaActual);
                        }
                        hojaActual = padre;
                        raizSinHijosMejores = false;
                        verificarHijos(hojasAEvitar, hijos);
                    }else{
                        //2.1.A
//                        System.out.println("cansadooooooooooooooooooooooooo");
                        arbol.cargarHijosDinamico(hojaActual);
                        hijos = hojaActual.getHijos();
                        raizSinHijosMejores = true;
                        verificarHijos(hojasAEvitar, hijos);
                    }
                }else{
                    //2.1.A
                    arbol.cargarHijosDinamico(hojaActual);
                    hijos = hojaActual.getHijos();
                    raizSinHijosMejores = false;
                    verificarHijos(hojasAEvitar, hijos);
                }
                if(hijos.size() != 0){
                    mejorTemp = hijos.get(0);
                    for (Iterator<Hoja> it = hijos.iterator(); it.hasNext();) {
                        Hoja hijo = it.next();
                        obtenerMetrica(hijo);
                        obtenerMetrica(hojaActual);
                        obtenerMetrica(mejorTemp);
                        //2.1.B
                        if(hijo.esEstadoFinal()){
                            optimo.add(hijo);
                            fin = true;
                            break;
                        }
                        //2.1.B
                        if(hijo.getEstado().getMetrica() < mejorTemp.getEstado().getMetrica()){
                            mejorTemp = hijo;
                        }
                    }//end for
                    if(fin){
                        break;
                    }
                    //2.1.C.
                    if(mejorTemp.getEstado().getMetrica() <= hojaActual.getEstado().getMetrica()){
                        tieneHijosMejores = true;
                        optimo.add(hojaActual);
                        hojaActual = mejorTemp;
                    }else{
//                        System.out.println("Hoja actual tiene mejor heurística que sus hijos --> " + hojaActual.toString());
                        //si es el raiz si o si selecciono al mejor hijo (aunque no tenga mejor heuristica)
                        if(raizSinHijosMejores){
                            hojaActual = mejorTemp;
                        }
                        tieneHijosMejores = false;
    //                    break;
                    }
                }
                else{
//                    System.out.println("Hoja actual sin hijos.");
                    if(hojaActual.getPadre() == null){
                        JOptionPane.showMessageDialog(null, "El algorítmo no encontró la solución.");
                        optimo = new ArrayList<Hoja>();
                        optimo.add(hojaActual);
                        break;
                    }
                    tieneHijosMejores = false;
//                    break;
                }
            }//end while
        }//end else
        arbol.setCaminoOptimo(optimo);
    }

    private List<Hoja> verificarHijos(List<Hoja> hojasAEvitar, List<Hoja> hijos){
        for (Iterator<Hoja> it = hojasAEvitar.iterator(); it.hasNext();) {
            Hoja hoja = it.next();
            if(hijos.contains(hoja)){
                hijos.remove(hoja);
            }
        }
        return hojasAEvitar;
    }

    @Override
    public String toString() {
        return "Escalada por máxima pendiente";
    }

    @Override
    public void obtenerMetrica(Hoja estado) {
        estado.getEstado().calcularMetrica(estadoFinal);
    }
}